package com.wsjc.common.redis;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.wsjc.common.redis.agent.JedisAgent;
import com.wsjc.common.redis.sentinels.JedisJavaSentinels;
import com.wsjc.common.redis.sentinels.JedisServerSentinels;

import redis.clients.jedis.Jedis;

/**
 * @描述: Redis缓存工具类.
 */
@Component("redisUtils")
public class RedisUtils {

	private  Logger logger = Logger.getLogger(RedisUtils.class);

	/** 默认缓存时间 */
	private  final int DEFAULT_CACHE_SECONDS = 60 * 60 * 1;// 单位秒 设置成一个钟

	@Value("${use.way.code}")
	private String useWayCode ;
	
	//默认java哨兵是关闭的
	@Value("${java.sentinel.open.status}")
	private boolean javaSentinelOpenStatus = false ;
	
	
	@Autowired
	private JedisAgent jedisAgent;
	
	
	public RedisUtils() {
		
	}
	
	/**
	 * 获取jedis 实例
	 * 代理，server哨兵，java哨兵
	 * @param key
	 * @return
	 */
	public  Jedis instanceJedisFactory(Object key) {
		
		Jedis jedis = null ;
		switch (useWayCode) {
			case "Agent":
				jedis = jedisAgent.newJedisInstance(key) ;
				break;
			case "JavaSentinel":
				// 开启java哨兵，并得到主线程的连接
				jedis = JedisJavaSentinels.getInstance(javaSentinelOpenStatus).newJedisInstance() ;
				break;
			case "ServerSentinel":
				jedis = JedisServerSentinels.newJedisInstance() ;
				break;
	
			default:
				logger.info("jedis instance init faild .");
				break;
		}
		
		return jedis ;
	}

	/**
	 * 释放redis资源
	 * @param jedis
	 */
	public  void releaseResource(Jedis jedis) {
		if (jedis != null) {
			jedis.close();
//			jedisSentinelPool.destroy(); 
//			jedisSentinelPool.returnResource(jedis);
		}
	}

	/**
	 * 删除Redis中的所有key
	 * 
	 * @param jedis
	 * @throws Exception
	 */
	public  void flushAll(Jedis jedis, Object key) {
		
		
		try {
			jedis.flushAll();
		} catch (Exception e) {
			logger.error("Cache清空失败：" , e);
		}
	}

	/**
	 * 保存一个对象到Redis中(缓存过期时间:使用此工具类中的默认时间) . <br/>
	 * 
	 * @param key
	 *            键 . <br/>
	 * @param object
	 *            缓存对象 . <br/>
	 * @return true or false . <br/>
	 * @throws Exception
	 */
	public  Boolean save(Jedis jedis, Object key, Object object) {
		return save(jedis, key, object, DEFAULT_CACHE_SECONDS);
	}

	/**
	 * 保存一个对象到redis中并指定过期时间
	 * 
	 * @param key
	 *            键 . <br/>
	 * @param object
	 *            缓存对象 . <br/>
	 * @param seconds
	 *            过期时间（单位为秒）.<br/>
	 * @return true or false .
	 */
	public  Boolean save(Jedis jedis, Object key, Object object, int seconds) {
		
		try {
			jedis.set(SerializeUtils.serialize(key), SerializeUtils.serialize(object));
			// = -1 不设置有效期，永久有效
			if(seconds != -1){
  			   jedis.expire(SerializeUtils.serialize(key), seconds);
			}
			return true;
		} catch (Exception e) {
			logger.error("Cache保存失败：", e);
			return false;
		}
	}

	/**
	 * 根据缓存键获取Redis缓存中的值.<br/>
	 * 
	 * @param key
	 *            键.<br/>
	 * @return Object .<br/>
	 * @throws Exception
	 */
	public  Object get(Jedis jedis, Object key) {
		
		try {
			byte[] obj = jedis.get(SerializeUtils.serialize(key));
			return obj == null ? null : SerializeUtils.unSerialize(obj);
		} catch (Exception e) {
			logger.error("Cache获取失败：" , e);
			return null;
		}
	}

	/**
	 * 根据缓存键清除Redis缓存中的值.<br/>
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public  Boolean del(Jedis jedis, Object key) {
		
		try {
			jedis.del(SerializeUtils.serialize(key));
			return true;
		} catch (Exception e) {
			logger.error("Cache删除失败：" , e);
			return false;
		}
	}

	/**
	 * 根据缓存键清除Redis缓存中的值.<br/>
	 * 
	 * @param keys
	 * @return
	 * @throws Exception
	 */
	public  Boolean del(Jedis jedis, Object... keys) {
		
		try {
			jedis.del(SerializeUtils.serialize(keys));
			return true;
		} catch (Exception e) {
			logger.error("Cache删除失败：" , e);
			return false;
		}
	}

	/**
	 * 
	 * @param key
	 * @param seconds
	 *            超时时间（单位为秒）
	 * @return
	 */
	public  Boolean expire(Jedis jedis, Object key, int seconds) {

		try {
			jedis.expire(SerializeUtils.serialize(key), seconds);
			return true;
		} catch (Exception e) {
			logger.error("Cache设置超时时间失败：" , e);
			return false;
		}
	}

	/**
	 * 添加一个内容到指定key的hash中
	 * 
	 * @param key
	 * @param field
	 * @param value
	 * @return
	 */
	public  Boolean addHash(Jedis jedis, String key, String field, String value) {
		
		try {
			jedis.hset(key, field, value); 
			return true;
		} catch (Exception e) {
			logger.error("Cache保存失败：" , e);
			return false;
		}
	}

	/**
	 * 从指定hash中拿一个对象
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public  String getHash(Jedis jedis, String key, String field) {
		
		try {
			String value = jedis.hget(key, field);
			return value;
		} catch (Exception e) {
			logger.error("Cache读取失败：" , e);
			return null;
		}
	}

	/**
	 * 从hash中删除指定filed的值
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public  Boolean delHash(Jedis jedis, Object key, Object field) {
		
		try {
			long result = jedis.hdel(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
			return result == 1 ? true : false;
		} catch (Exception e) {
			logger.error("Cache删除失败：" , e);
			return null;
		}
	}
	/**
	 * 验证该值，在hash中是否存在。
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public  Boolean existsHash(Jedis jedis, Object key, Object field) {
		
		try {
			Boolean result = jedis.hexists(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
			return result  ;
		} catch (Exception e) {
			logger.error("Cache验证hash 是否存在该值失败：" , e);
			return null;
		}
	}
	

	/**
	 * 拿到缓存中所有符合pattern的key
	 * 
	 * @param pattern
	 * @return
	 */
	public  Set<byte[]> keys(Jedis jedis, String pattern) {
		
		try {
			Set<byte[]> allKey = jedis.keys(("*" + pattern + "*").getBytes());
			return allKey;
		} catch (Exception e) {
			logger.error("Cache获取失败：" , e);
			return new HashSet<byte[]>();
		}
	}

	/**
	 * 获得hash中的所有key value
	 * 
	 * @param key
	 * @return
	 */
	public  Map<byte[], byte[]> getAllHash(Jedis jedis, Object key) {
		
		try {
			Map<byte[], byte[]> map = jedis.hgetAll(SerializeUtils.serialize(key));
			return map;
		} catch (Exception e) {
			logger.error("Cache获取失败：" , e);
			return null;
		}
	}
	
	/**
	 * 获得hash中的所有 values
	 * 
	 * @param key
	 * @return
	 */
	public  List<String> getAllValues(Jedis jedis, Object key) {
		
		try {
			List<String> list = jedis.hvals(String.valueOf(key));
			return list;
		} catch (Exception e) {
			logger.error("Cache获取失败：" , e);
			return null;
		}
	}
	
	/**
	 * 获得hash中的所有 key
	 * 
	 * @param key
	 * @return
	 */
	public  Set<String> getAllKeys(Jedis jedis, Object key) {
		
		try {
			Set<String> list = jedis.hkeys(String.valueOf(key));
			return list;
		} catch (Exception e) {
			logger.error("Cache获取失败：" , e);
			return null;
		}
	}

	/**
	 * 判断一个key是否存在
	 * 
	 * @param key
	 * @return
	 */
	public  Boolean exists(Jedis jedis, Object key) {
		
		Boolean result = false;
		try {
			result = jedis.exists(SerializeUtils.serialize(key));
			return result;
		} catch (Exception e) {
			logger.error("Cache获取失败：" , e);
			return false;
		}
	}
	
	/**
	 * 获取Redis中的key 的 ttl
	 * 
	 * @param jedis
	 * @throws Exception
	 */
	public  long getTtl(Jedis jedis, String key ) {
		
		try {
			return jedis.ttl(key) ;
		} catch (Exception e) {
			logger.error("Cache获取ttl失败：" , e);
		}
		return  0 ;
	}
	
	
	
	private static final String LOCK_NODE ="LOCK";
	private static final String LOCK_SUCCESS = "OK";
	private static final String SET_IF_NOT_EXIST = "NX";
	private static final String SET_WITH_EXPIRE_TIME = "PX";

	/**
	 * 尝试获取分布式锁
	 * 
	 * @param jedis      Redis客户端
	 * @param requestId  请求标识（随机数）
	 * @param expireTime 超期时间
	 * @return 是否获取成功
	 */
	public boolean tryGetDistributedLock(Jedis jedis, String requestId, int expireTime) {

		String result = jedis.set(LOCK_NODE, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

		if (LOCK_SUCCESS.equals(result)) {
			return true;
		}
		return false;
	}

	private static final Long RELEASE_SUCCESS = 1L;

	/**
	 * 释放分布式锁
	 * 
	 * @param jedis     Redis客户端
	 * @param requestId 请求标识（随机数）
	 * @return 是否释放成功
	 */
	public boolean releaseDistributedLock(Jedis jedis, String requestId) {

		String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
		Object result = jedis.eval(script, Collections.singletonList(LOCK_NODE), Collections.singletonList(requestId));

		if (RELEASE_SUCCESS.equals(result)) {
			return true;
		}
		return false;
	}

	/**
	 * 获取Incr
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public String getIncr(String key) {

		Jedis jedis = instanceJedisFactory(key);
		
		try {
			String result = String.valueOf(jedis.incr(key));
			return result;
		} catch (Exception e) {
			logger.error("自增1失败 是否存在该值失败：", e);
			return null;
		} finally {
			releaseResource(jedis);
		}
	}
	
	
	public String getUseWayCode() {
		return useWayCode;
	}

	public void setUseWayCode(String useWayCode) {
		this.useWayCode = useWayCode;
	}

	public boolean isJavaSentinelOpenStatus() {
		return javaSentinelOpenStatus;
	}

	public void setJavaSentinelOpenStatus(boolean javaSentinelOpenStatus) {
		this.javaSentinelOpenStatus = javaSentinelOpenStatus;
	}
	
	
	
	
	
	
	
	
	
	
	

}
